﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WHelper = PGMHelper.WilsonHelper;
using PGMHelper;
using System.Windows.Forms.DataVisualization.Charting;
using System.Drawing;

namespace HystereticBasic
{
    /// <summary>
    /// 一圈滞回环
    /// </summary>
    public class Cycle
    {
        /// <summary>
        /// I段加载-卸载路径
        /// </summary>
        private LoadingPath LoadPathI { set; get; }

        /// <summary>
        /// J段加载-卸载路径
        /// </summary>
        private LoadingPath LoadPathJ { set; get; }

        /// <summary>
        /// 24象限加载-卸载路径
        /// </summary>
        private LoadingPath LoadPathRegion24 { set; get; }

        /// <summary>
        /// 滞回环序号
        /// </summary>
        public int Index { set; get; }

        /// <summary>
        /// 累积能量
        /// </summary>
        public float AccEnergy { set; get; }

        /// <summary>
        /// 完整的加载路径
        /// </summary>
        public ForceDispObj WholeLoadPath
        {
            get
            {
                //初始化
                var path = new ForceDispObj(this.LoadPathI.LoadUnloadPath.ToList());
                //获得卸载路径
                var pathJ = this.LoadPathJ.LoadUnloadPath.ToList();
                //遍历数据
                for (int index = 1; index < pathJ.Count; index++)
                    path.Add(pathJ[index]);
                //获得24轴对象
                var path24 = this.LoadPathRegion24.LoadUnloadPath.ToList();
                for (int index = 1; index < path24.Count; index++)
                    path.Add(path24[index]);
                //返回对象
                return path;
            }
        }

        /// <summary>
        /// 获得力时程曲线
        /// </summary>
        public List<float> Forces
        {
            get
            {
                return this.WholeLoadPath.Forces;
            }
        }

        /// <summary>
        /// 获得位移时程曲线
        /// </summary>
        public List<float> Disps
        {
            get
            {
                return this.WholeLoadPath.Disps;
            }
        }

        /// <summary>
        /// 获得所有序号
        /// </summary>
        public List<int> Orders
        {
            get
            {
                return this.WholeLoadPath.Orders;
            }
        }

        /// <summary>
        /// 获得加载路径
        /// </summary>
        /// <param name="isPos"></param>
        /// <returns></returns>
        public ForceDispObj GetLoadingPathForceDispObj(bool isPos)
        {
            return this.GetLoadingPath(isPos).LoadUnloadPath;
        }

        /// <summary>
        /// 获得加载路径
        /// </summary>
        /// <param name="isPos"></param>
        /// <returns></returns>
        public MontForceDispObj GetLoadingPathForceDispObjWithoutUnload(bool isPos)
        {
            return this.GetLoadingPath(isPos).LoadingPathObj;
        }

        /// <summary>
        /// 获得加载路径
        /// </summary>
        /// <param name="isPos"></param>
        /// <returns></returns>
        public LoadingPath GetLoadingPath(bool isPos)
        {
            //加载路径存在数据
            if (this.LoadPathI.Count != 0 && this.LoadPathJ.Count != 0)
            {
                //正向加载
                if (isPos) return this.LoadPathI.isPosLoading ? this.LoadPathI : this.LoadPathJ;
                //反向加载
                else return this.LoadPathI.isPosLoading ? this.LoadPathJ :this.LoadPathI;
            }
            //都不存在数据
            else if (LoadPathI.Count == 0 && LoadPathJ.Count == 0)
                return new LoadingPath();
            //获得存在数据的对象
            var obj = LoadPathI.Count != 0 ? LoadPathI : LoadPathJ;
            //正向加载
            if (isPos) return obj.isPosLoading ? obj : new LoadingPath();
            else return obj.isPosLoading ? new LoadingPath() : obj;
        }

        /// <summary>
        /// 是否包含卸载段
        /// </summary>
        /// <param name="isPos"></param>
        /// <returns></returns>
        public bool isUnloadExist()
        {
            //获得加载路径
            var posLoading = this.GetLoadingPath(true);
            var negLoadging = this.GetLoadingPath(false);
            //都存在数据
            if (posLoading.Count != 0 && negLoadging.Count != 0)
                return posLoading.isUnloadExist && negLoadging.isUnloadExist;
            //都不存在数据
            else if (posLoading.Count == 0 && negLoadging.Count == 0)
                return false;
            //仅有一个对象
            else if (posLoading.Count != 0) return posLoading.isUnloadExist;
            else return negLoadging.isUnloadExist;
        }

        /// <summary>
        /// 是否包含卸载段
        /// </summary>
        /// <param name="isPos"></param>
        /// <returns></returns>
        public bool isUnloadExist(bool isPos)
        {
            return this.GetLoadingPath(isPos).isUnloadExist;
        }

        /// <summary>
        /// 获得单调线
        /// </summary>
        /// <param name="exclude24Obj"></param>
        /// <returns></returns>
        public List<MontForceDispObj> GetMonotonousList(bool exclude24Obj)
        {
            //初始化
            var objList = new List<MontForceDispObj> 
            {
                this.LoadPathI.LoadingPathObj,
                this.LoadPathI.UnlaodingPathObj,
                new MontForceDispObj()
            };
            //是否存在J端对象
            if(this.LoadPathJ.Count != 0)
            {
                var obj = this.LoadPathJ.LoadingPathObj;
                for (int index = 1; index < obj.Count; index++)
                    objList[1].Add(obj[index]);
                objList[2] = this.LoadPathJ.UnlaodingPathObj;
            }
            //24象限对象
            if(!exclude24Obj && this.LoadPathRegion24.Count != 0)
            {
                var obj = this.LoadPathRegion24.LoadingPathObj;
                for (int index = 1; index < obj.Count; index++)
                    objList[1].Add(obj[index]);
                objList[2] = this.LoadPathJ.UnlaodingPathObj;
            }
            return objList;
        }

        #region 滞回环特征

        /// <summary>
        ///  计算滞回环的平均割线刚度
        /// </summary>
        /// <returns></returns>
        public float GetSecantStiffness()
        {
            //获得刚度
            var posStiff = this.GetSecantStiffness(true);
            var negStiff = this.GetSecantStiffness(false);
            //都成功
            if (posStiff != 0 && negStiff != 0) return (posStiff + negStiff) * 0.5F;
            else if (posStiff != 0) return posStiff;
            else if (negStiff != 0) return negStiff;
            else return 0;
        }

        /// <summary>
        /// 计算滞回环的割线刚度
        /// </summary>
        /// <param name="isPos"></param>
        /// <param name="stiffness"></param>
        /// <returns></returns>
        public float GetSecantStiffness(bool isPos)
        {
            //获得对应的路径
            var pathObj = this.GetLoadingPath(isPos);
            //存在数据
            if (pathObj.Count == 0) return 0;
            //获得滞回数据的最大位移点
            var maxDisp = pathObj.PeakOreintedPt;
            //位移存在
            if (Math.Abs(maxDisp.Disp) < GlobalParam.DispTol) return 0;
            //刚度和位移是否同向
            if (maxDisp.Disp * maxDisp.Force < 0) return 0;
            //计算刚度
            return maxDisp.SecantStiffness;
        }

        /// <summary>
        /// 求滞回环面积
        /// </summary>
        /// <returns> 面积 </returns>
        public float GetA()
        {
            return this.LoadPathI.GetEnergy() + this.LoadPathJ.GetEnergy();
        }

        /// <summary>
        /// 求滞回环面积
        /// </summary>
        /// <param name="isPos"></param>
        /// <returns></returns>
        public float GetA(bool isPos)
        {
            return this.GetLoadingPath(isPos).GetEnergy();
        }

        /// <summary>
        /// 计算等效阻尼比
        /// </summary>
        /// <returns></returns>
        public float GetViscousDampingRatio()
        {
            //获得单圈滞回面积
            float A = this.GetA();
            //获得对应的路径
            var posObj = this.GetLoadingPath(true);
            var negObj = this.GetLoadingPath(false);
            //三角形面积
            var maxDispA = posObj.Count == 0 ? 0 : posObj.VirtualPeakOreintedForcePt.GetA();
            var minDispA = negObj.Count == 0 ? 0 : negObj.VirtualPeakOreintedForcePt.GetA();
            //计算面积总和
            var virtualA = maxDispA + minDispA;
            //返回粘滞阻尼系数
            return virtualA == 0 ? 0: A / (2f * (float)Math.PI * virtualA);
        }

        /// <summary>
        /// 计算单向的等效阻尼比
        /// </summary>
        /// <param name="isPos"></param>
        /// <returns></returns>
        public float GetViscousDampingRatio(bool isPos)
        {
            //能量
            var A = this.GetA(isPos);
            //获得对应的路径
            var pathObj = this.GetLoadingPath(isPos);
            //存在数据
            if (pathObj.Count == 0) return 0;
            //计算三角面积
            var virtualA = pathObj.VirtualPeakOreintedForcePt.GetA();
            //返回
            return virtualA == 0? 0: A / (2f * (float)Math.PI * virtualA); 
        }
        
        /// <summary>
        /// 滞回环最大位移
        /// </summary>
        /// <returns></returns>
        public float GetMaxDisp()
        {
            //获得最大位移
            var posDisp = this.GetMaxDisp(true);
            var negDisp = this.GetMaxDisp(false);
            //保留大值
            return Math.Abs(posDisp) > Math.Abs(negDisp) ? posDisp : negDisp;
        }

        /// <summary>
        /// 获得最大位移
        /// </summary>
        /// <param name="isPos"></param>
        /// <returns></returns>
        public float GetMaxDisp(bool isPos)
        {
            //返回位移
            return this.GetPeakOrientPt(isPos).Disp;
        }

        /// <summary>
        /// 获得残余变形
        /// </summary>
        /// <param name="isPos"></param>
        /// <returns></returns>
        public float GetUnloadDisp()
        {
            //获得最大位移
            var posDisp = this.GetUnloadDisp(true);
            var negDisp = this.GetUnloadDisp(false);
            //保留大值
            return Math.Abs(posDisp) > Math.Abs(negDisp) ? posDisp : negDisp;
        }

        /// <summary>
        /// 获得残余变形
        /// </summary>
        /// <param name="isPos"></param>
        /// <returns></returns>
        public float GetUnloadDisp(bool isPos)
        {
            //获得路径
            var path = this.GetLoadingPath(isPos);
            //不存在卸载段：虚拟卸载点
            if (!this.isUnloadExist(isPos))
                return path.VirtualUnloadPt.Disp;
            //峰值位移
            var dispDt = path.PeakOreintedPt;
            //残余位移
            var unloadDisp = this.GetUnloadPt(isPos).Disp;
            //是否同向
            return dispDt.Disp * unloadDisp >= 0? unloadDisp: 0;
        }

        /// <summary>
        /// 残余变形系数
        /// </summary>
        /// <param name="isPos"></param>
        /// <returns></returns>
        public float GetUnloadDispRatio()
        {
            //获得最大位移
            var posRatio = this.GetUnloadDispRatio(true);
            var negRatio = this.GetUnloadDispRatio(false);
            //保留大值
            return Math.Abs(posRatio) > Math.Abs(negRatio) ? posRatio : negRatio;
        }

        /// <summary>
        /// 残余变形系数
        /// </summary>
        /// <param name="isPos"></param>
        /// <returns></returns>
        public float GetUnloadDispRatio(bool isPos)
        {
            //获得路径
            var path = this.GetLoadingPath(isPos);
            //不存在卸载段：虚拟卸载点
            if (!this.isUnloadExist(isPos))
            {
                //虚拟卸载点
                var ptDisp = path.VirtualUnloadPt.Disp;
                //虚拟点存在
                if (Math.Abs(ptDisp) > GlobalParam.DispTol)
                    return 1;
            }
            //峰值变形
            var maxDisp = this.GetMaxDisp(isPos);
            //变形存在
            return maxDisp == 0 ? 0 : this.GetUnloadDisp(isPos) / maxDisp;
        }

        /// <summary>
        /// 环最大承载力
        /// </summary>
        /// <returns></returns>
        public float GetMaxForce()
        {
            //获得最大位移
            var posForce = this.GetMaxForce(true);
            var negForce = this.GetMaxForce(false);
            //保留大值
            return Math.Abs(posForce) > Math.Abs(negForce) ? posForce : negForce;
        }

        /// <summary>
        /// 环最大承载力
        /// </summary>
        /// <param name="isPos"></param>
        /// <returns></returns>
        public float GetMaxForce(bool isPos)
        {
            return this.GetPeakForcePt(isPos).Force;
        }

        /// <summary>
        /// 峰值指向点位于24象限
        /// </summary>
        /// <param name="isPos"></param>
        /// <returns></returns>
        public bool isPeakOreintedInRegion24(bool isPos)
        {
            return this.GetLoadingPath(isPos).isPeakOreintedInRegion24;
        }

        /// <summary>
        /// 获得峰值指向点
        /// </summary>
        /// <param name="isPos"></param>
        /// <returns></returns>
        public ForceDispBasicPair GetPeakOrientPt(bool isPos)
        {
            return this.GetLoadingPath(isPos).PeakOreintedPt;
        }

        /// <summary>
        /// 峰值力点
        /// </summary>
        /// <param name="isPos"></param>
        /// <returns></returns>
        public ForceDispBasicPair GetPeakForcePt(bool isPos)
        {
            return this.GetLoadingPath(isPos).PeakForcePt;
        }

        /// <summary>
        /// 残余变形点
        /// </summary>
        /// <param name="isPos"></param>
        /// <returns></returns>
        public ForceDispBasicPair GetUnloadPt(bool isPos)
        {
            return this.GetLoadingPath(isPos).UnloadPt;
        }

        #endregion

        #region DATA and Chart

        /// <summary>
        /// 滞回环数据
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public GridViewDatas GetData(string title, bool isNorminal)
        {
            //获得完整路径
            var wholeLoadPath = this.WholeLoadPath;
            //不进行归一化
            if (!isNorminal)
                return wholeLoadPath.GetData(string.Format("{0}滞回环{1}", title, this.Index));
            //判断是否存在数据点
            if (wholeLoadPath.Count == 0) return new GridViewDatas();
            //归一化
            var maxDisp = wholeLoadPath.DispMaxPoint.Disp;
            var maxForce = wholeLoadPath.ForceMaxPoint.Force;
            var minDisp = wholeLoadPath.DispMinPoint.Disp;
            var minForce = wholeLoadPath.ForceMinPoint.Force;
            //初始化
            var forceDispObj = new ForceDispObj();
            //添加数据
            for (int i = 0; i < wholeLoadPath.Count; i++)
            {
                //获得对象
                var obj = wholeLoadPath[i];
                //放缩
                var disp = obj.Disp >= 0 ? obj.Disp / maxDisp : obj.Disp / minDisp * -1;
                var force = obj.Force >= 0 ? obj.Force / maxForce : obj.Force / minForce * -1;
                forceDispObj.Add(new ForceDispBasicPair(obj.Order, disp, force));
            }
            return forceDispObj.GetData(string.Format("{0}滞回环{1}", title, this.Index));
        }

        /// <summary>
        /// 绘制滞回环
        /// </summary>
        /// <param name="chart"></param>
        /// <param name="index"></param>
        public void ToChart(Chart chart)
        {
            //获得完整路径
            var wholeLoadPath = this.WholeLoadPath;
            //序列名称
            var name = string.Format("滞回环{0}", this.Index);
            //添加序列
            wholeLoadPath.ToChart(chart, name, 2);
        }

        /// <summary>
        /// 绘制滞回环
        /// </summary>
        /// <param name="chart"></param>
        /// <param name="index"></param>
        public void ToChart(Chart chart, Color color, int borderWith, bool isSolid)
        {
            //获得完整路径
            var wholeLoadPath = this.WholeLoadPath;
            //序列名称
            var name = string.Format("滞回环{0}", this.Index);
            //添加序列
            wholeLoadPath.ToChart(chart, name, color, borderWith, isSolid);
        }

        #endregion

        #region Construction

        /// <summary>
        /// 滞回环平滑
        /// </summary>
        /// <returns></returns>
        public Cycle GetSmoothCycle()
        {
            //构造滞回环
            var cycle = new Cycle(this.Index);
            //对象I存在数据点
            if (this.LoadPathI.Count != 0)
                cycle.LoadPathI = this.LoadPathI.GetSmoothLoadingPath();
            //对象J存在数据点
            if (this.LoadPathJ.Count != 0)
                cycle.LoadPathJ = this.LoadPathJ.GetSmoothLoadingPath();
            //对象24存在数据点
            if (this.LoadPathRegion24.Count != 0)
                cycle.LoadPathRegion24 = this.LoadPathRegion24.GetSmoothLoadingPath();
            //返回滞回环
            return cycle;
        }

        /// <summary>
        /// 滞回环代数化
        /// </summary>
        /// <returns></returns>
        public Cycle GetNumericalCycle()
        {
            //构造滞回环
            var cycle = new Cycle(this.Index);
            //对象I存在数据点
            if (this.LoadPathI.Count != 0)
                cycle.LoadPathI = this.LoadPathI.GetNumericalLoaindgPath();
            //对象J存在数据点
            if (this.LoadPathJ.Count != 0)
                cycle.LoadPathJ = this.LoadPathJ.GetNumericalLoaindgPath();
            //对象24存在数据点
            if (this.LoadPathRegion24.Count != 0)
                cycle.LoadPathRegion24 = this.LoadPathRegion24.GetNumericalLoaindgPath();
            //返回滞回环
            return cycle;
        }

        /// <summary>
        /// 获得试验滞回环
        /// 通过骨架曲线加以限定
        /// </summary>
        /// <param name="skeletonObj"></param>
        /// <returns></returns>
        public Cycle GetPostExpCycle(MontForceDispObj posSkeleton, 
            MontForceDispObj negSkeleton)
        {
            //构造滞回环
            var cycle = new Cycle(this.Index);
            //对象I存在数据点
            if (this.LoadPathI.Count != 0)
                cycle.LoadPathI = this.LoadPathI.GetPostExpLoadingPath(this.LoadPathI.isPosLoading?
                    posSkeleton : negSkeleton);
            //对象J存在数据点
            if (this.LoadPathJ.Count != 0)
                cycle.LoadPathJ = this.LoadPathJ.GetPostExpLoadingPath(this.LoadPathJ.isPosLoading ?
                    posSkeleton : negSkeleton);
            //对象24存在数据点
            if (this.LoadPathRegion24.Count != 0)
                cycle.LoadPathRegion24 = this.LoadPathRegion24;
            //返回滞回环
            return cycle;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="loadPathi"></param>
        /// <param name="loadPathj"></param>
        public Cycle(LoadingPath loadPathi, LoadingPath loadPathj, 
            int index, ref float energy)
            :this(index)
        {
            //获得I段路径
            this.LoadPathI = loadPathi;
            //判断是否落于24象限
            if(loadPathj.isPeakOreintedInRegion24)
            {
                this.LoadPathRegion24 = loadPathj;
                energy += this.LoadPathRegion24.GetEnergy();
            }
            //获得J段路径
            else this.LoadPathJ = loadPathj;
            //计算累积耗能
            energy += this.GetA();
            this.AccEnergy = energy;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="loadPathi"></param>
        public Cycle(LoadingPath loadPathi, int index, ref float energy)
            : this(index)
        {
            this.LoadPathI = loadPathi;
            energy += this.GetA();
            this.AccEnergy = energy;
        }

        /// <summary>
        /// 空的构造函数
        /// </summary>
        public Cycle(int index)
        {
            //获得序号
            this.Index = index;
            //初始化
            this.LoadPathI = new LoadingPath();
            this.LoadPathJ = new LoadingPath();
            this.LoadPathRegion24 = new LoadingPath();
        }

        #endregion
    }
}
